home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 016a / 4d_while.zip / WHILE.TXT < prev    next >
Text File  |  1991-11-18  |  11KB  |  241 lines

  1.  
  2.              Whiling Away in 4DOS
  3.  
  4.                   by
  5.  
  6.  
  7.              Marshall E. Giguere
  8.  
  9.               November 17, 1991
  10.  
  11. If you're familiar with the constructions supported by structured
  12. programming languages you'll be used to having available things like
  13. "while", "repeat" etc. in the language.  This is not, however, the
  14. case where DOS COMMAND.COM and 4DOS are concerned.  DOS has no
  15. support for any structured language constructions and 4DOS supports
  16. only "if/then/else" constructs.  Although neither language supports
  17. the "while" construct a "while" can be simulated, and in the case of
  18. 4DOS formalized into a convention supported by a couple of simple
  19. aliases. That's what this little article is about.
  20.  
  21.            What to do When You don't have a WHILE!
  22.  
  23. If you're working with a language like 4DOS that doesn't have a
  24. "while" you can simulate the behavior of a "while" by remembering
  25. the following things about a while:
  26.  
  27.     * logical testing happens at the top of the loop.
  28.     * the loop only executes if the test is TRUE.
  29.     * at the end of the code block you always branch 
  30.       back to the top.
  31.  
  32. With these three simple rules you can write a "while" loop using
  33. nothing but "if" and "goto" (yes, the dreaded & dangerous GOTO).
  34. The result is less than appealing, and is certainly confusing to the
  35. eye of the reader.  If, God forbid, you're working in DOS COMMAND.COM
  36. and you need to repeat a section of code over which some condition
  37. holds true the result is truly horrific.  Let's say you need to
  38. iterate over a block of code while the variable "i" is less than ten,
  39. here's what the DOS COMMAND.COM equivalent would look like:
  40.  
  41. :loop
  42. if %i GT 10 GOTO endloop
  43.     .
  44.     .
  45.     do something interesting
  46.     set i=%@eval[%i + 1]
  47.     .
  48.     .
  49.     goto loop
  50. :endloop
  51.  
  52.  
  53. Notice that it requires the creation of two labels to make an
  54. equivalent "while" in DOS COMMAND.COM.  You can achieve the same
  55. result in 4DOS at the expense of only one label with an "if/then"
  56. (see below).
  57.  
  58. :loop
  59. iff %i LT 10 then
  60.     .
  61.     .
  62.     do something interesting
  63.     set i=%@eval[%i + 1]
  64.     .
  65.     .
  66.     goto loop
  67. endiff
  68.  
  69. *NOTE:    it is assumed that "i" is initialized to some reasonable
  70.     value before entering the loop. 
  71.  
  72. You'll notice immediately that the resulting 4DOS code is a bit
  73. easier on the eye and saved one label.  The above code still, to my
  74. mind, does not convey the directly fact that an iteration is in
  75. progress until one has scanned the entire block of code up to the
  76. "goto loop" statement, it's still just an "if" statement.
  77.  
  78. As you can see we can achieve in effect the semantics of a "while"
  79. using nothing but "if" and "goto".  It is also possible to do the
  80. same for the "repeat/until" or "do/while" constructs by moving the
  81. logical tests to the bottom of the loop, that is left as an exercise
  82. for the reader.  The next logical question is "how can we have the
  83. syntax and the semantics of iteration in 4DOS", and that is the
  84. subject of the next section.
  85.  
  86.                 WHILE You Wait
  87.  
  88. Before we begin constructing of a "while" language element for 4DOS I
  89. should probably discuss, briefly, why go through this exercise
  90. anyway, and discuss some design goals to be achieved.  Then we can
  91. proceed directly to the implementation of the WHILE construct.
  92.  
  93. Why invent a WHILE language element at all is probably the question
  94. on your mind.  After all in the preceding section I proved
  95. conclusively that a WHILE can be simulated with the basic language
  96. elements "testing" and "branching".  Isn't that sufficient?  The
  97. answer is yes it's sufficient, but no, it doesn't convey the direct
  98. semantics of the operation "while".  We must examine the "if/goto"
  99. code block in some detail to determine that an iteration on some
  100. condition is in effect.  With a "while" construction the semantics of
  101. the conditional iteration are readily apparent, i.e. the syntax and
  102. the semantics are in harmony.  By this I simply mean that the
  103. conveyed and computed meaning of a "while" construction are identical.
  104. Whenever possible programming language designers have an obligation
  105. to assure the user that the conveyed and computed semantics are in
  106. harmony.  Having established that linguistic harmony is a reasonable
  107. and useful goal let's look at the implementation goals next.
  108.  
  109. Implementation of a "while" construction for 4DOS should encompass a
  110. few simple goals and ideas:
  111.  
  112.     1. the "while" should be clean as possible.
  113.     2. permit the full complement of all possible 4DOS
  114.        conditionals. 
  115.     3. be reasonably simple to use.
  116.     4. be nestable.
  117.  
  118. The above goals all come into conflict when we consider that in order
  119. to implement a "while" it is necessary at the end of the loop to
  120. branch back to the beginning.  A branch requires that we know in
  121. advance where it is intended that the end of the loop branch back to,
  122. this can only be resolved through the use of a label statement.  The
  123. obvious question here is how will such a label be generated, and
  124. unfortunately the answer is that you the programmer must generate the
  125. label manually.  This is the one ugliness I've had to endure for the
  126. clarity I desire.  The problem then is how to incorporate the
  127. labeling into the methodology without creating something really ugly.
  128. My goal is still to create something reasonably pleasing to the eye.
  129. Since we must declare the branch back label I decided to make a
  130. virtue of the necessity and incorporate the requirement into the
  131. language elements.  Item 2 above is easily accommodated with the 4DOS
  132. "iff" which covers a host of possible conditionals.  The final
  133. result, I hope you'll agree, meets goal 3, simplicity of use.
  134.  
  135. Obviously we need to know two things for the "while" loop to work
  136. properly: where does it start and where does it end. These functions
  137. are accomplished by introducing two new 4DOS language elements (in
  138. the form of aliases) "while" and "endwhile".  The "while" alias
  139. starts things off be declaring the conditional and bracketing the
  140. beginning of the code block to be executed if the condition is valid.
  141. The "endwhile" must serve two purposes: force an unconditional branch
  142. to the beginning of the loop and act as the closure for when
  143. (eventually) the "while" conditional evaluates to false, i.e. this is
  144. where you go when the loop is complete.  Here are the two aliases for
  145. implementing the "while" loop in 4DOS:
  146.  
  147. WHILE=`iff %& then`
  148. ENDW*HILE=`goto %1^endiff`
  149.  
  150. As you can see the "WHILE" alias is a disguised "iff" which will
  151. swallow any string and treat it as a conditional expression.  The
  152. "then" clause of the "iff" opens the code block, and this is where
  153. you supply any code plus code to modify the conditional variable(s)
  154. so the loop reaches closure.  The "ENDWHILE" alias takes one
  155. argument the name of the label which bounds the top of the loop and
  156. supplies the needed "endiff" to allow 4DOS to find the closure point
  157. when the "while" conditional finally fails.  Obviously just using
  158. these aliases as is isn't quite enough, remember I said you had to
  159. supply the label to bound the loop.  This simply means at the top of
  160. the loop you must declare the label that will be used to control the
  161. unconditional "goto" in the "endwhile".  The label you declare at the
  162. top of the "while" and the one in the "endwhile" must be the same.
  163. Here's where necessity becomes virtue.  By declaring the label at the
  164. top and bottom of the "while" some documentation is built into the
  165. language, making it obvious which "endwhile" belongs to which
  166. "while", this is especially useful in a nested "while" situation.
  167.  
  168. Let's write a simple "while" that prints the numbers from 0 to 10
  169. using the new "WHILE" aliases.
  170.  
  171. @echo off
  172. set i=0
  173.  
  174. :while1
  175. while %i LE 10
  176.      echo i = %i
  177.      set i=%@eval[%i+1]
  178. endwhile while1
  179.  
  180.  
  181. As you see in the above code the "while" begins with the declaration
  182. of the top bounding label ":while1".  Next we see the "while" with its
  183. conditional expression which states that the loop executes "while"
  184. "%i" is less than or equal to ten.  The "endwhile" declares the end
  185. of the "while" and tells us (and 4DOS) where to go at the end of each
  186. pass through the loop, in this case the label ":while1".  Sandwiched
  187. in between is the code block which is executed on every pass through
  188. the loop.  The result, I hope you'll agree, isn't too ugly and does
  189. what I intended, i.e. conveys the semantics and the syntax of a
  190. "while" loop.
  191.  
  192.                  Restrictions
  193.  
  194. Since the "while" aliases are in fact a 4DOS "iff/then^endiff" all
  195. the same restrictions apply to nesting.  You cannot nest more that
  196. eight levels of "iff" or "while" in any combination.  Further to
  197. avoid dangling "iff" closures you should close each "iff" with an
  198. "endiff".  This will prevent 4DOS from becoming clinically confused
  199. and leaping as it were to the wrong "conclusion" (endiff).
  200.  
  201.                  Portability
  202.  
  203. The problem with building language constructs out of aliases/macros
  204. is the same faced by code library builders.  That simply is that you
  205. must distribute your "library" with your code.  The same is true
  206. here, you must hand-out the "while" aliases with any 4DOS batch file
  207. you create that uses them.  This can be a painful problem since one
  208. tends to forget something that in effect becomes part of the
  209. language.  This is especially true if a macro fits into the native
  210. language so well that you forget it is just that an macro, you take
  211. it for granted.  All this just goes to say that any batch files you
  212. create using the "while/endwhile" aliases will require that the
  213. aliases accompany the batch file.
  214.  
  215.               Concluding remarks
  216.  
  217. Although the "while/endwhile" isn't perfect meaning labels must be
  218. declared the result isn't too ugly and the obligatory labels provide
  219. some use as documentation.  I tried all kinds of ideas out to rid
  220. myself of the necessity of physically declaring the "while" labels,
  221. but 4DOS' mechanism for resolving labels is too simple-minded, i.e.
  222. 4DOS does a simple textual search with no expansion for labels.  This
  223. simply means you can't created a computed label, or hide one in an
  224. alias.  But, in the mean time the affect is achievable with aliases.
  225.  
  226. Maybe someday 4DOS will actually implement a "while" and other
  227. structured programming language constructs?  The problem that must be
  228. addressed by the implementers of 4DOS is the same one I encountered,
  229. i.e. how to manufacture and track labels.  One is tempted to suggest
  230. the use of byte offset signatures to obviate the need to declare
  231. labels.  Simply put when a "while" is encountered its byte-offset is
  232. pushed onto a context stack.  When and "endwhile" is encountered it
  233. is likewise pushed onto the context stack and the last pushed "while"
  234. offset is used to get back to the most resent "while".  If the while
  235. continues its "endwhile" is popped and execution continues through
  236. the loop, if the "while" fails the "while" and "endwhile" offsets are
  237. popped and a jump to the statement following the "endwhile" offset is
  238. executed.  This is a fully reenterant process and may be implemented
  239. to any reasonable number of levels. Hey, Rex, it's only a suggestion.
  240.  
  241.